import WebApp from '@twa-dev/sdk'
import { TOTAL_USER, REFRESH_TOTAL_USERS_INTERVAL, SECOND_MILL, CHARGING, CHARGING_TIME } from '../constants'
import Recaptcha from '../google/recaptcha'
import { User } from '../interface/user'
import { Router } from '../router'
import { UserResponse } from '../service/interface'
import { isDev, isProduction } from './check'
import { formatBase64Image } from './common'
import { dataFromLocalStore, removeFromLocalStore, saveToLocalStore } from './store'

let g_user_info: User | undefined = undefined
const USER_INFO = 'USER_INFO_2' // if user info interface change by request, change the versin. for example: USER_INFO_3
const INITDATA = 'INITDATA_1'

export const saveUserData = (info: UserResponse) => {
    const name = info.username || info.nickName;
    const current = new Date().getTime();
    const authDate = info.authDate || current;

    const data: User = {
        inviteUrl: info.inviteUrl,
        email: name,
        customerId: String(info.id),
        token: info.token,
        icon: formatBase64Image(info.image) || '',
        username: name,
        inviter: info.parentName,
        authDate,
        inviterUsername: info.parentUserName,
        expiredDate: authDate + 2592000000 // 30 day
    }
    localStorage.setItem(USER_INFO, JSON.stringify(data))
    g_user_info = data;
    return data;
}

export const fetchUserData = (): User | undefined => {
    if (g_user_info) {
        return g_user_info
    }
    try {
        const str = window.localStorage.getItem(USER_INFO);
        if (!str) {
            return undefined
        }
        const data = JSON.parse(str)
        g_user_info = data
        return data
    } catch (error) {
        return undefined
    }
}

export const saveToken = (token: string) => {
    if (!token) {
        return
    }
    try {
        const str = JSON.stringify({ token })
        window.localStorage.setItem(INITDATA, str)
    } catch (error) {
        // empty
    }
}

export const fetchToken = () => {
    const userInfo = fetchUserData();
    const token = userInfo?.token || ''
    if (token) {
        return token
    }

    try {
        const str = window.localStorage.getItem(INITDATA)
        if (str) {
            const info = JSON.parse(str)
            return info.token || ''
        }
        return ''
    } catch (error) {
        return ''
    }
}

export const logout = () => {
    window.localStorage.removeItem(USER_INFO);
    window.localStorage.removeItem(INITDATA);
    g_user_info = undefined;
    Recaptcha.removeRobotCheck();
    window.location.replace(`#${Router.Login}`)
}

export const unsupport = () => {
    Recaptcha.removeRobotCheck();
    window.location.replace(`#${Router.Unsupport}`)
}

export const checkUserValid = (): boolean => {
    const user = fetchUserData()
    const isCurrentUser = (isDev() && !WebApp.initData) ? true : WebApp.initDataUnsafe.user?.id && (String(WebApp.initDataUnsafe.user.id) === user?.customerId)
    if (user?.token && user?.customerId && isCurrentUser) {
        // check authDate
        if (isProduction()) {
            if (!user.expiredDate || (new Date().getTime() > user.expiredDate)) {
                return false
            }
        }
        return true
    }
    return false
}

export const formatInitData = (initData?: string): { auth_date?: string, user?: { id: number; first_name: string; last_name: string }, [key: string]: any } => {
    const result: { [key: string]: any } = {}
    if (!initData) {
        return result;
    }

    try {
        const params = new URLSearchParams(initData)
        params.forEach((v, k) => {
            result[k] = k === 'user' ? JSON.parse(v) : v;
        })
    } catch (error) {
        // temp
    }

    return result
}

const fetchLastUsersData = (): { count: number, time: number } | undefined => {
    const str = dataFromLocalStore(TOTAL_USER);
    if (!str) {
        return
    }

    try {
        const info = JSON.parse(str);
        if (info && info.count < 0) {
            info.count = 0;
        }
        return info
    } catch (error) {
        return
    }
}

// time: second
export const saveTotalUsersCountIfNeeded = (num: number | string, time?: number): { count: number, speed: number } => {

    if (!time) {
        time = Math.floor(new Date().getTime() / SECOND_MILL)
    }

    const count = Number(num)
    const lastData = fetchLastUsersData()
    if (!lastData) {
        saveToLocalStore(TOTAL_USER, JSON.stringify({ count, time }));
        return { count, speed: 0 }
    }

    const diff = time - lastData.time;
    if (diff > REFRESH_TOTAL_USERS_INTERVAL) {
        const redundant = diff / REFRESH_TOTAL_USERS_INTERVAL - 1
        const currentCount = (count - lastData.count) / REFRESH_TOTAL_USERS_INTERVAL * redundant + lastData.count
        saveToLocalStore(TOTAL_USER, JSON.stringify({ count: currentCount, time }));
        return { count: currentCount, speed: (count - currentCount) / REFRESH_TOTAL_USERS_INTERVAL }
    }

    if (diff <= 0) {
        return { count, speed: 0 }
    }

    return { count: lastData.count, speed: (count - lastData.count) / REFRESH_TOTAL_USERS_INTERVAL }
}

export const saveTotalUsersCount = (num: number | string, time?: number) => {
    if (!time) {
        time = Math.floor(new Date().getTime() / SECOND_MILL)
    }

    const count = Number(num)
    const lastData = fetchLastUsersData()
    if (lastData && count < lastData.count) {
        saveToLocalStore(TOTAL_USER, JSON.stringify({ count: lastData.count, time }));
        return;
    }
    saveToLocalStore(TOTAL_USER, JSON.stringify({ count, time }));
}

export const fetchLastTotalUserCount = (): number => {
    return fetchLastUsersData()?.count || 0
}

export const mosaicEmail = (str?: string, mosaicLength = 3): string => {
    if (!str) {
        return ''
    }
    const idx = str.indexOf('@');
    if (idx === -1) {
        return str;
    }
    const start = idx < 5 ? 1 : Math.floor((idx - mosaicLength) / 2)
    const end = idx < 5 ? idx - 1 : start + mosaicLength
    const mosaic = new Array(end - start).fill('*').join('')

    return `${str.substring(0, start)}${mosaic}${str.substring(end, str.length)}`
}

// Charging
export const saveChargingTime = () => {
    saveToLocalStore(CHARGING, String(new Date().getTime()))
}

export const chargingTime = (): number => {
    const time = dataFromLocalStore(CHARGING)
    if (time === null) {
        return 0
    }

    const threshold = CHARGING_TIME;
    const diff = (new Date().getTime() - Number(time)) / SECOND_MILL;
    if (diff >= threshold) {
        removeFromLocalStore(CHARGING)
        return 0
    }
    return threshold - diff;
}

